<script setup lang="ts">
import type { PropType } from 'vue'
import { Search } from 'lucide-vue-next'
import { computed, nextTick, reactive, ref, toRaw, watch } from 'vue'
import type { TableInstance, TableRowSelection, TreeInstance } from '@arco-design/web-vue'
import { getOrgTree, getPersonalPagerModel } from '@/api'
import { filterTreeData } from '@/utils/tools'
import ValidateTagInput from '@/components/common/ValidateTagInput.vue'

defineOptions({ name: 'UserTagInput' })

const $props = defineProps({
  data: {
    type: Array as PropType<Record<string, unknown>[]>,
    default: () => [],
  },
  modalTitle: {
    type: String as PropType<string>,
    default: '人员选择',
  },
  multiple: {
    type: Boolean as PropType<boolean>,
    default: true,
  },
  rowKey: {
    type: String as PropType<string>,
    default: 'id',
  },
  required: {
    type: Boolean as PropType<boolean>,
    default: true,
  },
  validator: {
    type: Function as PropType<() => boolean>,
    default: undefined,
  },
})
const $emits = defineEmits(['update:data', 'change'])
defineSlots<{ default: () => any }>()

const modalVisible = ref(false)
const modalValues = ref<string[]>([])
const modalCheckedValues = ref<any[]>([])

const computedTags = computed<string[]>({
  get: () => {
    if (Array.isArray(toRaw($props.data))) {
      return $props.data.map(i => i.name as string)
    }
    return []
  },
  set: (names) => {
    const newValues = modalCheckedValues.value.filter(i => names.includes(i.name))
    $emits('update:data', newValues)
    $emits('change', newValues)
  },
})

watch(
  () => $props.data,
  () => {
    modalValues.value = ($props.data || []).map(i => i[$props.rowKey] as string)
    modalCheckedValues.value = [...($props.data || [])]
  },
  { immediate: true, deep: true },
)

const loading = ref(false)
const orgData = ref<any[]>([])
const orgTreeRef = ref<TreeInstance>()
const personData = ref<any[]>([])
const totalPerson = ref(0)
const orgFilterText = ref('')
const pagination = ref({ pageSize: 15, pageNum: 1 })
const entity = ref({ companyId: '', keyword: '' })
const rowSelection = reactive<TableRowSelection>({
  type: $props.multiple ? 'checkbox' : 'radio',
  showCheckedAll: false,
  onlyCurrent: false,
})
const personTableRef = ref<TableInstance>()

const columns = computed(() => [
  { title: '姓名', dataIndex: 'name' },
  { title: '电话', dataIndex: 'mobile' },
  { title: '邮箱', dataIndex: 'mail' },
  { title: '公司名称', dataIndex: 'companyName' },
  { title: '部门名称', dataIndex: 'deptName' },
])

const computedOrgData = computed(() => {
  return filterTreeData(orgData.value, 'name', orgFilterText.value)
})

function commonAttrFilter(r: any) {
  return {
    id: r.id,
    name: r.name,
    code: r.code,
    email: r.email,
    mobile: r.mobile,
    companyName: r.companyName,
    deptName: r.deptName,
  }
}

async function getOrgTreeData() {
  try {
    orgData.value = await getOrgTree()
    await nextTick()
    orgTreeRef.value?.expandAll(true)
  }
  catch (e) {
    console.error(e)
    orgData.value = []
  }
}
async function getPersonPageData(pageNum?: number) {
  try {
    loading.value = true
    if (pageNum) {
      pagination.value.pageNum = pageNum
    }
    const {
      data: { rows, total },
    } = await getPersonalPagerModel({
      pager: pagination.value,
      entity: entity.value,
    })
    personData.value = (rows || []).map(commonAttrFilter)
    totalPerson.value = total
  }
  catch (e) {
    console.error(e)
    personData.value = []
    totalPerson.value = 0
  }
  finally {
    loading.value = false
  }
}
const findIdx = (person: any, key: string) => person[$props.rowKey] === key
function updateSelectOrg(_, data) {
  const { node } = data
  entity.value.companyId = node.companyId
  getPersonPageData(1)
}
function toggleRowSelect(row) {
  const key = row[$props.rowKey]
  const selected = modalCheckedValues.value.findIndex(i => findIdx(i, key)) > -1
  personTableRef.value?.select(row[$props.rowKey], !selected)
  // 需要手动触发选中数据更新
  changeSelect(row, key)
}
function changeSelect(_, key) {
  if ($props.multiple) {
    const idx = modalCheckedValues.value.findIndex(i => findIdx(i, key))
    if (idx > -1) {
      modalCheckedValues.value.splice(idx, 1)
    }
    else {
      modalCheckedValues.value.push(personData.value.find(i => findIdx(i, key)))
    }
  }
  else {
    modalCheckedValues.value = [personData.value.find(i => findIdx(i, key))]
  }
}
function removeCheckedValue(item: any, idx: number) {
  modalValues.value = modalValues.value.filter(i => i !== item[$props.rowKey])
  modalCheckedValues.value.splice(idx, 1)
}

function updateModalValues() {
  $emits('update:data', [...modalCheckedValues.value])
  $emits('change', [...modalCheckedValues.value])
}

async function openModal() {
  try {
    loading.value = true
    modalVisible.value = true
    await getOrgTreeData()
    await getPersonPageData()
  }
  finally {
    loading.value = false
  }
}
</script>

<template>
  <a-input-group>
    <ValidateTagInput
      v-if="!$slots.default && required"
      v-model="computedTags"
      :max-tag-count="3"
      :validator="validator"
      placeholder="请选择人员"
    />
    <a-input-tag
      v-if="!$slots.default && !required"
      v-model="computedTags"
      :max-tag-count="3"
      :disabled-input="true"
      placeholder="请选择人员"
    />
    <slot />
    <a-button type="primary" @click="openModal">
      <Search :size="14" />
    </a-button>
  </a-input-group>

  <a-drawer
    v-model:visible="modalVisible"
    width="80vw"
    :title="modalTitle"
    @ok="updateModalValues"
  >
    <a-spin
      :loading="loading"
      style="width: 100%; height: calc(100vh - 142px); overflow: hidden; box-sizing: border-box"
    >
      <div class="tag-input-flex">
        <div class="header-tags">
          <a-tag
            v-for="(i, idx) in modalCheckedValues"
            :key="i[rowKey]"
            color="arcoblue"
            closable
            @close="removeCheckedValue(i, idx)"
          >
            {{ i.name }}
          </a-tag>
        </div>
        <div class="tag-input-grid" style="--columns: 360px 1fr">
          <div class="left-org-tree">
            <a-input-group>
              <a-input
                v-model="orgFilterText"
                placeholder="Please enter a name"
                allow-clear
              />
              <a-button type="primary">
                <Search :size="14" />
              </a-button>
            </a-input-group>
            <div class="tree-content">
              <a-tree
                ref="orgTreeRef"
                :data="computedOrgData"
                :field-names="{ title: 'name', key: 'id' }"
                size="mini"
                block-node
                default-expand-all
                @select="updateSelectOrg"
              />
            </div>
          </div>
          <div class="right-table">
            <a-input-group>
              <a-input
                v-model="entity.keyword"
                placeholder="请输入您的工号、姓名、手机号码"
                allow-clear
              />
              <a-button type="primary" @click="getPersonPageData(1)">
                <Search :size="14" />
              </a-button>
            </a-input-group>
            <div class="table-content">
              <a-table
                ref="personTableRef"
                v-model:selected-keys="modalValues"
                :row-key="rowKey"
                :scroll="{ y: '100%' }"
                :row-selection="rowSelection"
                :columns="columns"
                :data="personData"
                :pagination="{
                  current: pagination.pageNum,
                  pageSize: pagination.pageSize,
                  total: totalPerson,
                  pageSizeOptions: [15, 30, 50, 100],
                  showTotal: true,
                  showPageSize: true,
                }"
                @row-click="toggleRowSelect"
                @select="changeSelect"
                @page-change="getPersonPageData"
                @page-size-change="(val) => (pagination.pageSize = val) && getPersonPageData(1)"
              />
            </div>
          </div>
        </div>
      </div>
    </a-spin>
  </a-drawer>
</template>
